package org.td.engine.entity;

import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import org.td.engine.map.GameMap;
import org.td.engine.PickFilter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class EntityEnvironment {
    
    private List<Entity> entityList;
    private List<ParticleEffect> particleList;
    private ParticleFactory particleFactory;
    private GameMap gameMap;

    public EntityEnvironment(GameMap gameMap) {
        particleFactory = new ParticleFactory();
        entityList = new ArrayList<Entity>();
        particleList = new ArrayList<ParticleEffect>();
        this.gameMap = gameMap;
    }

    private List<ParticleEffect> particleListBuffer = new ArrayList<ParticleEffect>();

    public void addParticle(ParticleEffect particleEffect) {
        particleListBuffer.add(particleEffect);
    }

    public ParticleFactory getParticleFactory() {
        return particleFactory;
    }
    
    public List<Entity> pickEntities(PickFilter filter) {
        List<Entity> output = new ArrayList<Entity>();
        for (Entity e : entityList) {
            if (filter.accept(e)) {
                output.add(e);
            }
        }
        
        return Collections.unmodifiableList(output);
    }

    public Entity pickEntity(PickFilter filter) {
        for (Entity e : entityList) {
            if (filter.accept(e)) {
                return e;
            }
        }

        return null;
    }
    
    public Entity pickNearest(float x, float y, PickFilter filter) {
        if (entityList.isEmpty()) {
            return null;
        }
        
        Entity nearest = null;
        double nearestDist = Double.MAX_VALUE;
        for (Entity e : entityList) {
            if (filter.accept(e)) {
                float newDist = distanceBetween(x, y, e);
                if (newDist < nearestDist) {
                    nearestDist = newDist;
                    nearest = e;
                }
            }
        }
        
        return nearest;
    }
    
    public static float distanceBetween(float x, float y, Entity e2) {
        return (float)Math.sqrt((x - e2.getX())*(x - e2.getX()) + (y - e2.getY())*(y - e2.getY()));
    }

    private List<Entity> entityListBuffer = new ArrayList<Entity>();
    
    public void addEntity(Entity e) {
        entityListBuffer.add(e);
    }

    public void removeEntity(Entity e) {
        e.markClear();
    }
    
    public void render(SpriteBatch batch) {
        for (Entity e : entityList) {
            e.render(batch);
        }

        for (ParticleEffect p : particleList) {
            p.draw(batch);
        }
    }
    
    public void update(float time) {
        entityList.addAll(entityListBuffer);
        entityListBuffer.clear();
        for (Iterator<Entity> i = entityList.iterator(); i.hasNext(); ) {
            Entity e = i.next();

            e.update(time);
            if (e.canClear()) {
                i.remove();
            }
        }

        particleList.addAll(particleListBuffer);
        particleListBuffer.clear();
        for (Iterator<ParticleEffect> i = particleList.iterator(); i.hasNext(); ) {
            ParticleEffect p = i.next();

            p.update(time);
            if (p.isComplete()) {
                i.remove();
            }

        }

    }

    public void dispose() {
        particleFactory.dispose();
    }
    
    public int indexedToX(int indexX) {
        return GameMap.absoluteX(indexX);
    }
    
    public int indexedToY(int indexY) {
        return GameMap.absoluteY(indexY);
    }

    public int getCellWidth() {
        return gameMap.getTileWidth();
    }

    public int getCellHeight() {
        return gameMap.getTileHeight();
    }
}
